package com.atzxh.guigu.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author 小红同学
 * @date 2023-12-11-22:30
 * @description
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {

        // 创建ServerSocketChannel  ==>  ServerSocket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 得到一个selector对象
        Selector selector = Selector.open();

        // 绑定一个端口6666，在服务器端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 把serverSocketChannel 注册到 selector ，关心的事件为 OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环等待客户端连接】
        while (true) {

            // 这里等待一秒，如果没有事件发生，则返回
            if (selector.select(1000) == 0) {
                System.out.println("服务器等待一秒，无连接");
                continue;
            }

            // 如果返回大于0， 就获取相关的 SelectionKey 集合
            // 通过 selectionKeys 可以反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            // 使用迭代器遍历集合
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();

            while (keyIterator.hasNext()) {
                SelectionKey selectionKey = keyIterator.next();
                // 根据 key 对应的通道发生的事件做相应的处理
                if (selectionKey.isAcceptable()) {  // 如果是OP_ACCEPT，则有客户端连接
                    // 为该客户端生成一个 socketChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();

                    // 此时连接成功
                    System.out.println("客户端连接成功 ========  " + socketChannel.hashCode());

                    // 将 channel 设置成非阻塞模式 ，否则报错 java.nio.channels.IllegalBlockingModeException
                    socketChannel.configureBlocking(false);

                    // 将该 socketChannel 注册到 selector ，关注事件为 OP_READ
                    // 并关联一个buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }

                // 发生 OP_READ
                if (selectionKey.isReadable()) {
                    // 通过 key 反向获取 channel
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    // 获取该通道关联的buffer
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    // 读取buffer
                    channel.read(byteBuffer);
                    System.out.println("from 客户端 ========== " + new String(byteBuffer.array()));
                }

                // 手动删除当前的 selectionKey ，防止重复操作
                keyIterator.remove();
            }
        }
    }
}
